﻿
#pragma once

#include "can_launch.h"


//template<class U>static  U  CheckNoConst( );         
//void(U::*)(float)

#if 0
template<class U>static                                                            \
    void  Check(  typename ::tools::sfinae::Transform<U,T>::CMethod );                 \

#endif

#define DETECTED_MEMBER(member_name)                                                   \
template<class C,class T> struct check_no_const_##member_name: ::tools::sfinae::YesNo  \
{                                                                                      \
    template<class U>static                                                            \
    U  Check(  typename ::tools::sfinae::Transform<U,T>::Method );                     \
    template<class U>static  void Check( ... );                                        \
    typedef decltype( Check<C>(&C::member_name) ) Type;                                \
    enum { eIS_AVAILABLE = std::is_same<Type, C>::value };                             \
};                                                                                     \
template<class C,class T> struct check_const_##member_name: ::tools::sfinae::YesNo     \
{                                                                                      \
    template<class U>static                                                            \
    U  Check(  typename ::tools::sfinae::Transform<U,T>::CMethod );                    \
    template<class U>static  void Check( ... );                                        \
    typedef decltype( Check<C>(&C::member_name) ) Type;                                \
    enum { eIS_AVAILABLE = std::is_same<Type, C>::value };                             \
};                                                                                     \
                                                                                       \
template<class C, class T, int FORDATA = ::std::is_function<T>::value >                \
struct has_##member_name                                                               \
{                                                                                      \
    DETECTED_MEMBER_BY_NAME(member_name);                                              \
    enum { eIS_NOCONST   = 0 };                                                        \
    enum { eIS_CONST     = 0 };                                                        \
    enum { eIS_AVAILABLE = available_data(C, T, member_name) };                        \
};                                                                                     \
template< class C, class T> struct has_##member_name<C,T,1>                            \
{                                                                                      \
    DETECTED_MEMBER_BY_NAME(member_name);                                              \
    enum { eCAN_CONST    = can_launch_cmethod(C, T, member_name) };                    \
    enum { eCAN_NO_CONST = can_launch_method (C, T, member_name) };                    \
                                                                                       \
    typedef ::tools::sfinae::Failed Failed;                                            \
                                                                                       \
    typedef check_no_const_##member_name<C,T> ToNoConst;                               \
    typedef typename                                                                   \
        ::std::conditional<eCAN_NO_CONST && !eCAN_CONST, ToNoConst, Failed >::type NoConst;          \
                                                                                       \
    typedef check_const_##member_name<C,T> ToConst;                                    \
    typedef typename                                                                   \
        ::std::conditional<eCAN_CONST, ToConst, Failed >::type Const;                  \
                                                                                       \
    enum { eIS_NOCONST   = NoConst::eIS_AVAILABLE   };                                 \
    enum { eIS_CONST     = Const::eIS_AVAILABLE     };                                 \
    enum { eIS_AVAILABLE = eIS_NOCONST || eIS_CONST };                                 \
};

//has_##member_name<class_name, member_type>::eIS_AVAILABLE    